package com.sun.electric.compression.api

import java.util.concurrent.Callable
import com.sun.electric.compression.bzip2.BZip2BitOutputStream
import com.sun.electric.compression.bzip2.BZip2BlockCompressor
import com.sun.electric.compression.bzip2.BZip2HuffmanStageEncoder
import com.sun.electric.compression.bzip2.BZip2DivSufSort
import com.sun.electric.compression.bzip2.BZip2Constants
import com.sun.electric.compression.bzip2.BZip2MTFAndRLE2StageEncoder

/**
 * @see BZip2BlockCompressor
 * @author Daniel.Schmidt
 */
class BZIP2BlockCompressorScala(
    bitOutputStream : BZip2BitOutputStream, 
    blockSize : Int) extends BZip2BlockCompressor(bitOutputStream, blockSize) with Callable[BZIP2BlockCompressorScala] {

  /* The huffman encoder containing the preprocessed block data */
  var huffmanEncoder : BZip2HuffmanStageEncoder = null
  /* The CRC of the current block header */
  var headerCRC : Int = 0
  /* The starting point of the bwt */
  var bwtStartPointer : Int = 0
  
  /**
   * Preprocesses the block data, initializes the huffman encoder and stores
   * all informations that shall be written in the file.
   */
  override def call() : BZIP2BlockCompressorScala = {
    
    var info : BZIP2BlockCompressorScala = null
    
    if(!isEmpty()) {
      
    	// If an RLE run is in progress, write it out
		if (this.rleLength > 0) {
			writeRun (this.rleCurrentValue & 0xff, this.rleLength);
		}

		// Apply a one byte block wrap required by the BWT implementation
		this.block(this.blockLength) = this.block(0);

		// Perform the Burrows Wheeler Transform
		val divSufSort : BZip2DivSufSort = new BZip2DivSufSort (this.block, this.bwtBlock, this.blockLength);
		bwtStartPointer = divSufSort.bwt();
		
		headerCRC = this.crc.getCRC()

		// Perform the Move To Front Transform and Run-Length Encoding[2] stages 
		val mtfEncoder : BZip2MTFAndRLE2StageEncoder= new BZip2MTFAndRLE2StageEncoder (this.bwtBlock, this.blockLength, this.blockValuesPresent);
		mtfEncoder.encode();

		
		// Perform the Huffman Encoding stage and write out the encoded data
		huffmanEncoder = new BZip2HuffmanStageEncoder (this.bitOutputStream, mtfEncoder.getMtfBlock(), mtfEncoder.getMtfLength(), mtfEncoder.getMtfAlphabetSize(), mtfEncoder.getMtfSymbolFrequencies());
		
		//Encodes the data with the huffman encoding.
		//Notice: the encoded data isn't written to the file yet.
		huffmanEncoder.encode()
		info = this
    }
    return info
  }
  
  def getHeaderCRC() : Int = headerCRC
  def getBwtStartPointer() : Int = bwtStartPointer
  def getEncoder() : BZip2HuffmanStageEncoder = huffmanEncoder
}